﻿/*  (c) 2008 Benjamin Schroeter
 *  You are allowed to use this code in all your commercial, non-commercial, open and closed source projects.
 *  But you have to leave this Copyright message in all files. This code is provided "as is" without warranty of any kind.
 *  If you have any enhancements or bug reports I will appreciate a short feedback.
 *  For more information visit the article to this code on my blog at 
 *  http://www.ticklishtechs.net/2008/04/12/to-restrict-dynamically-the-usage-of-domain-properties-in-dsl-models/ */

using System.ComponentModel;

namespace BenjaminSchroeter.Dsl.UserRestrictions
{
    /// <summary>
    /// A CustomTypeDescriptor for Shapes that will be used to restrict 
    /// the properties list.
    /// 
    /// All other methodes will be delegated to the default TypeDescriptor.
    /// </summary>
    public class RestrictedShapeTypeDescriptor : CustomTypeDescriptor
    {
        private readonly int RestrictionMode;
        private readonly object instance;
        private readonly TypeDescriptionProvider parentTypeDescriptionProvider;

        /// <summary>
        /// Initializes a new instance of the <see cref="RestrictedShapeTypeDescriptor"/> class.
        /// </summary>
        /// <param name="restricionMode">The selected restricion mode. Based on this value the properties list will be manipulated.</param>
        /// <param name="instance">The instance to create a TypeDescriptor for.</param>
        /// <param name="parent">The parent TypeDescriptorProvider.</param>
        public RestrictedShapeTypeDescriptor(int restricionMode, object instance, TypeDescriptionProvider parent)
        {
            this.RestrictionMode = restricionMode;
            this.instance = instance;
            this.parentTypeDescriptionProvider = parent;
        }

        /// <summary>
        /// Returns a collection of property descriptors for the object represented by this type descriptor.
        /// </summary>
        /// <returns>
        /// A <see cref="T:System.ComponentModel.PropertyDescriptorCollection"/> containing the property descriptions for the object represented by this type descriptor. The default is <see cref="F:System.ComponentModel.PropertyDescriptorCollection.Empty"/>.
        /// </returns>
        public override PropertyDescriptorCollection GetProperties()
        {
            PropertyDescriptorCollection properties = parentTypeDescriptionProvider.GetTypeDescriptor(instance).GetProperties();

            if (RestrictionMode > 0)
            {
                object[] attributes = instance.GetType().GetCustomAttributes(typeof (RestrictedPropertyAttribute), true);
                foreach (RestrictedPropertyAttribute attr in attributes)
                    if ( attr.RestrictionMode == RestrictionMode)
                        if (attr.Restriction != Restriction.Full)
                        {
                            PropertyDescriptor prop = properties.Find(attr.PropertyName, true);

                            if (prop != null)
                            {
                                if (attr.Restriction == Restriction.Hidden)
                                    properties.Remove(prop);
                                else if (attr.Restriction == Restriction.ReadOnly)
                                {
                                    PropertyDescriptor propreadonly = new ReadOnlyPropertyDescriptor(prop);
                                    properties.Remove(prop);
                                    properties.Add(propreadonly);
                                }
                            }
                        }
            }

            return properties;
        }
    }
}
